package utils

import (
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"time"
)

func init() {
	//不要启动这么快
	time.Sleep(time.Millisecond * 20)
}

// GetTableName 获取表名
func GetTableName(table interface{}) string {
	v := reflect.ValueOf(table)
	if v.Kind() == reflect.Ptr {
		mth := v.MethodByName("TableName")
		if !mth.IsValid() {
			t := v.Type()
			//log.Println(t.Elem().Name(), v.Elem().Type().Name())
			//return t.Name()
			name := t.Name()
			if name == "" {
				return t.Elem().Name()
			}
			return name
		}
		res := mth.Call(nil)
		return res[0].String()
	} else if v.Kind() == reflect.String {
		return v.String()
	} else if v.Kind() != reflect.Struct {
		panic("Unsuport type")
	}

	v = reflect.New(v.Type())
	mth := v.MethodByName("TableName")
	if !mth.IsValid() {
		t := v.Type()
		return t.Name()
	}
	res := mth.Call(nil)
	return res[0].String()
}

// Sleep 精确睡眠，当前时间到t时间范围 大于 指定的时间，不睡眠，否则睡眠剩下的时间
func Sleep(t *time.Time, ms int64) {
	msec := time.Duration(ms) * time.Millisecond
	s := time.Since(*t)
	if msec > s {
		msec -= s
		time.Sleep(msec)
	}
}

// Show 显示窗口，Windows 下有效
func Show() (err error) {
	ShowWindow(true)
	return
}

// Hide 关闭窗口，Windows 下有效
func Hide() (err error) {
	ShowWindow(false)
	return
}

// Restart 重启进程
func Restart() (err error) {
	var cmd *exec.Cmd
	if len(os.Args) == 1 {
		cmd = exec.Command(os.Args[0])
	} else {
		cmd = exec.Command(os.Args[0], os.Args[1:]...)
	}
	err = cmd.Start()
	if err == nil {
		os.Exit(1)
	}
	return err
}

// DelayRestart 延时重启
func DelayRestart(sec int64) {
	go func() {
		time.Sleep(time.Second * time.Duration(sec))
		err := Restart()
		log.Println("Restart:", err)
	}()
}

// Move 移动文件
func MoveFile(src, dest string) (err error) {
	dir := filepath.Dir(dest)
	os.MkdirAll(dir, 0775)

	fs, err := os.Open(src)
	if err != nil {
		return
	}
	fd, err := os.Create(dest)
	if err != nil {
		fs.Close()
		return
	}
	_, err = io.Copy(fd, fs)
	if err != nil {
		return
	}
	fs.Close()
	fd.Close()

	fi, err := os.Stat(src)
	if err == nil {
		os.Chmod(dest, fi.Mode())
		os.Chtimes(dest, time.Now(), fi.ModTime())
	}

	os.Remove(src)
	return
}

func Move(src, dest string) (err error) {
	fi, err := os.Stat(src)
	if err != nil {
		return
	}
	if fi.IsDir() {
		if !strings.HasSuffix(src, "/") {
			src += "/"
		}
		if !strings.HasSuffix(dest, "/") {
			dest += "/"
		}
	} else {
		return MoveFile(src, dest)
	}

	ds, err := os.ReadDir(src)
	if err != nil {
		return
	}
	for _, d := range ds {
		if d.IsDir() {
			//log.Println(d.Name())
			mode := os.ModeDir
			fi, er := d.Info()
			if er == nil {
				mode = fi.Mode()
			}
			os.MkdirAll(dest+d.Name(), mode)
			err = Move(src+d.Name(), dest+d.Name()+"/")
			if err != nil {
				//log.Println(err)
				return
			}
		} else {
			//err = MoveFile(src+d.Name(), dest+d.Name())
			for i := 0; i < 3; i++ {
				err = os.Rename(src+d.Name(), dest+d.Name())
				if err != nil {
					log.Println(err)
					time.Sleep(time.Second)
					continue
				}
				break
			}
		}
	}
	os.Chtimes(dest, time.Now(), fi.ModTime())
	return os.Remove(src)
}
